home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume12 / mush / part17 < prev    next >
Encoding:
Text File  |  1990-05-05  |  54.9 KB  |  1,879 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i045: Mail User's Shell, Part17/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 45
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part17
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 17 (of 19)."
  18. # Contents:  mush/README-7.1 mush/hdr_sw.c mush/malloc.c
  19. #   mush/misc_frame.c mush/strings.c
  20. # Wrapped by argv@turnpike on Wed May  2 13:59:49 1990
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'mush/README-7.1' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'mush/README-7.1'\"
  24. else
  25. echo shar: Extracting \"'mush/README-7.1'\" \(11036 characters\)
  26. sed "s/^X//" >'mush/README-7.1' <<'END_OF_FILE'
  27. XThis is release 7.1.0 of the SunView implementation of mush.
  28. X
  29. XVersion 7.1.0 differs from 7.0.4 mostly in the appearance of the screen
  30. Xand the additional functionality that is allowed to show through to the
  31. Xtool from the underlying interpreter.  This is a significant enough change
  32. Xin "look and feel" that the revision number was increased from 0 to 1.
  33. X
  34. XThanks to Bill Randle <billr@saab.cna.tek.com> for extensive SunOS 3.5
  35. Xtesting, and to Bill and also Don Lewis <del@mlb.semi.harris.com> for
  36. Xtheir contributions to the new toolmode composition features and function
  37. Xkey handling.
  38. X
  39. XTool mode changes include:
  40. X    * Compilation now keys on definitions of SUN_4_1, SUN_4_0 or SUN_3_5
  41. X      in makefile.sun, rather than assuming SunOS4.0 when SIGRET=void.
  42. X      You still have to define SUNTOOL to get the tool mode capability.
  43. X      If you define SUNTOOL but not the others, SUN_4_0 is assumed.
  44. X    * The header summary display window has a scrollbar; the <Prev> and
  45. X      <Next> buttons for scrolling are gone.
  46. X    * The placement of buttons and items has changed a lot.  Buttons and
  47. X      items dealing with folders and general setup have moved to the top
  48. X      of the frame, and items dealing with individual messages and with
  49. X      composition have been placed in a single row between the headers
  50. X      and messsage display subwindows.
  51. X    * The <Folders> and <Save> buttons each have a text entry item.
  52. X      Furthermore, file completion with the ESC key works in those items.
  53. X    * The <Sort> menu has been unscrambled, so you actually get the sort
  54. X      criteria that you select.  (Don't ask.)
  55. X    * The <Aliases> and <Headers> buttons have moved into a menu under
  56. X      the <Options> button.  This clears up some confusion about exactly
  57. X      what it was that <Headers> meant, and provides a hook for future
  58. X      addition of a window for defining your own outgoing message headers.
  59. X    * The <Display> button is gone; its operations are now handled by
  60. X      opening the <Options> frame and toggling show_deleted or no_reverse.
  61. X    * The small one-line print window is gone; messages previously shown
  62. X      there now go to the scrollable status window.  There may be some
  63. X      remaining bugs with missing newlines here.  This frees up some more
  64. X      file descriptors in SunOS 3.5, to keep other things working longer.
  65. X    * Function keys are recognized in most parts of the main frame.  In
  66. X      anticipation of the day when window manager function keys can be
  67. X      redefined, the messages about "L7 not defined" etc. are still shown
  68. X      unless suppressed through $quiet (see below).
  69. X    * The composition frame has more control buttons, providing more of
  70. X      the functions of line and curses mode message composition.  Some
  71. X      of the "chattiness" of message composition has gone away.  In fact,
  72. X      the whole chatty subwindow in the compose frame has gone away,
  73. X      possibly to return in a later patch when a better way to decide
  74. X      what frame a message should go to has been worked out.  In the
  75. X      meantime, all messages go to the main frame.
  76. X    * Tilde escapes are supported in the tool mode composition textsw,
  77. X      with a few minor exceptions accessible from the control buttons.
  78. X    * Typing a <return> while entering header field text in tool mode
  79. X      will move automatically to the next header when this is sensible.
  80. X      The cursor becomes a bent arrow to indicate that this will happen.
  81. X    * User-definable icons can be installed through the $mail_icon and
  82. X      $newmail_icon variables, and $quiet has a field to suppress the
  83. X      message-number label so your pretty pictures won't be trashed.
  84. X    * Files that are not readable as folders are left out of the menus
  85. X      for the <Folder> and <Save> items.
  86. X
  87. XGeneral changes include:
  88. X
  89. X    * There is a new defined constant, DIRECTORY, which indicates whether
  90. X      your system has BSD-compatible directory-access routines.  It turns
  91. X      out to be much too hard to figure this out on an OS-by-OS basis.  
  92. X      DIRECTORY is automatically defined when BSD is defined, and is in
  93. X      the default CFLAGS in makefile.hpux; you others are on your own.
  94. X    * Some compilers were confused by "/*" appearing in the META string
  95. X      defined in glob.h.  The characters in META have been rearranged.
  96. X    * Using "exit" in a nested "if" in a source/init file no longer
  97. X      causes error messages about "missing endif".
  98. X    * Redefining "folder" via a "cmd" in .mushrc no longer causes the
  99. X      initial folder load to bomb.  Similarly with "sort".
  100. X    * Date parsing and sorting now understand timezones.  There may
  101. X      still be some rough edges in date parsing on some of the less
  102. X      common date formats, but RFC-822 and ctime (From_ line) dates
  103. X      are handled correctly.  If the dates mush displays are really
  104. X      off the wall, the order of the sscanf's in parse_date() may need
  105. X      to be changed, or we may need to add some cases rather than
  106. X      using partial matches to skip missing timezone fields.  There
  107. X      are also some strange nonstandard abbreviations out there (what,
  108. X      for example, is ECT?) which will all be treated as GMT unless
  109. X      you hack them into the tables in dates.c.  Missing timezones are
  110. X      treated as the local zone to get the date-received right (the
  111. X      From_ line ctime-date almost never has a timezone).
  112. X    * Mush now warns you if a file you attempt to load does not "look
  113. X      like" a folder (i.e. no messages can be read).  If you are already
  114. X      in the shell, this leaves you in an empty folder as it did before.
  115. X      If you are just starting up (e.g. with "mush -f"), mush will exit.
  116. X    * Additional checking is now done when collecting new mail and when
  117. X      updating folders to detect corruptions, warn the user, and allow
  118. X      a chance to recover.  Mush still reinitializes the spool folder if
  119. X      it shrinks, but if this is detected at update time (as opposed to
  120. X      new-mail-check time), the user is allowed to abort the update and
  121. X      salvage the current folder contents.
  122. X    * Curses mode now respects the user's presetting of $crt, unless the
  123. X      user's value is larger than the actual screen size.  This allows
  124. X      "set crt=2" to be used to force use of $pager.
  125. X
  126. XChanges in commands:
  127. X
  128. Xmush -h -
  129. X    The -h (-draft) option will now accept "-" as a filename indicating
  130. X    standard input.  Note that this causes the input message to be sent
  131. X    immediately; interactive use cannot be combined with redirected input.
  132. X    The internal "mail -h" command will NOT interpret "-" as standard in.
  133. X
  134. Xalts *user
  135. X    This syntax, analogous to the $autosign2 syntax, allows you to specify
  136. X    any user name anywhere as "you" for purposes of $metoo, etc.
  137. X
  138. Xfolder -n
  139. X    This command changes folders without updating; it replaces the old
  140. X    "folder !" notation, though the old form is still supported.  See
  141. X    also the general notes above for behavior on attempts to load files
  142. X    that are not folders.
  143. X
  144. Xfrom pattern
  145. X    Given an argument that is not parseable as a message list, "from" will
  146. X    automatically invoke "pick -f pattern".  Mixing message lists and
  147. X    patterns is slightly counter-intuitive; if the message list precedes
  148. X    the pattern, it will restrict the pattern search to that list, e.g.
  149. X    "from 3-7 johnsmith" will show those messages in the range 3-7 that
  150. X    are from johnsmith.  If the message list follows the pattern, it will
  151. X    not be detected at all, but will be considered part of the pattern.
  152. X    Also, "from jim bob sally" will treat the entire "jim bob sally" list
  153. X    as a single pattern, as "pick" would; this may change in the future.
  154. X
  155. Xpipe -p /pat1/,/pat2/
  156. X    The pattern supplied may now have the form /pat1/,/pat2/ to indicate
  157. X    that extraction should begin at pat1 and end at pat2, inclusive.
  158. X    Patterns are still matched literally at beginning-of-line (no regex
  159. X    matching), and there is not currently any way to imbed a slash in
  160. X    patterns of this form.  To allow searching for file paths, slashes
  161. X    are significant only if the second slash is followed by a comma.
  162. X
  163. Xsave/copy
  164. X    Unless told to clobber the file (-f), these commands now check that
  165. X    the file to which they are appending "looks like" a folder.  If the
  166. X    file seems to be something else, the user is prompted to confirm the
  167. X    save or copy.
  168. X
  169. Xset
  170. X    Several minor fixes.  Piping to "set" now clears the variable if the
  171. X    input message list is empty, rather than leaving the old value.  For
  172. X    backwards compatibility, however, an unset variable does not become
  173. X    set when an empty message list is piped to it.  Also, some of the
  174. X    more esoteric abuses of the variable=value syntax have either been
  175. X    made legal (`set var=' is the same as `set var') or made illegal
  176. X    (`set var=value = value' won't create a variable named "var=value").
  177. X
  178. Xsort
  179. X    Sorting by multiple criteria at once is now supported.  The flags to
  180. X    sort have changed; "-" to reverse sorting is now obsolete, replaced
  181. X    by "-r", and all the sort criteria should now be prefixed with a "-"
  182. X    (-a,-d,-l,-R,-s,-S) like options to any other command.  A significant
  183. X    subset of the old syntax is still recognized as a special case.
  184. X
  185. XNew/changed variables:
  186. X
  187. X    $cmd_help
  188. X    (Also $tool_help)  The path given for this variable may contain
  189. X    the usual filename metacharacters (~+).
  190. X
  191. X    $hangup
  192. X    When set, mush updates the folder on SIGHUP instead of saving
  193. X    the tempfile.  This is a bit dangerous -- in rare circumstances
  194. X    (mainly when two or more MUAs are modifying the same folder)
  195. X    some new mail could be lost.  Old mail should never be lost.
  196. X
  197. X    $hdr_format
  198. X    The format spec %Z returns the time zone part of the date.
  199. X
  200. X    $mail_icon
  201. X    Names an icon file to be used in the normal case, when no new
  202. X    mail is present.  This icon will replace the mailbox with the
  203. X    flag down.
  204. X
  205. X    $newmail_icon
  206. X    Names an icon file to be used when new mail is present, replacing
  207. X    the mailbox with the flag up.
  208. X
  209. X    $output
  210. X    The message-list output of the last successful command is stored
  211. X    in this variable.  This allows easy recovery from broken pipes
  212. X    etc.  Note that any successful command that does not produce a
  213. X    message list will clear $output (e.g. "echo").
  214. X
  215. X    $quiet
  216. X    If the field "newmail" is present in the multi-value, the usual
  217. X    "New mail (#X): ..." messages are not displayed.  The new mail
  218. X    is still automatically incorporated into the mailbox.  In tool
  219. X    mode, this shuts off the new mail bell (the "tool" field still
  220. X    silences ALL tool mode bells).
  221. X
  222. X    If the field "fkey" is present in tool mode, warning messages
  223. X    about unbound keys are not printed.
  224. X
  225. X    If the field "iconlabel" is present in tool mode, the current
  226. X    number of messages is not displayed in the mush icon.
  227. X    
  228. X    $status
  229. X    This is set to the success (0) or failure (-1) status of the
  230. X    previously executed command.  Note that some curses-mode commands
  231. X    return a failure status to indicate that the display has been
  232. X    corrupted even if the command itself succeeded, so this variable
  233. X    is mostly useful in scripts.
  234. END_OF_FILE
  235. if test 11036 -ne `wc -c <'mush/README-7.1'`; then
  236.     echo shar: \"'mush/README-7.1'\" unpacked with wrong size!
  237. fi
  238. # end of 'mush/README-7.1'
  239. fi
  240. if test -f 'mush/hdr_sw.c' -a "${1}" != "-c" ; then 
  241.   echo shar: Will not clobber existing file \"'mush/hdr_sw.c'\"
  242. else
  243. echo shar: Extracting \"'mush/hdr_sw.c'\" \(11559 characters\)
  244. sed "s/^X//" >'mush/hdr_sw.c' <<'END_OF_FILE'
  245. X/* @(#)hdr_sw.c    (c) copyright    2/17/90 (Dan Heller) */
  246. X
  247. X/* This file handles all the header subwindow code.  It would be much
  248. X * better if this subwindow, which displays the headers for the current
  249. X * folder, were a textsw.  That way, this file would go away completely.
  250. X * Until then, we have to create the window (canvas), define an event
  251. X * handler for when events happen in this window, create our own scrollbar,
  252. X * figure out when the user scrolls with it, attach our own popup menu to
  253. X * the canvas, handle events for that, let's see... kitchen sink?  Oh,
  254. X * that's over there in the corner.
  255. X */
  256. X#include "mush.h"
  257. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  258. X#include <sunwindow/win_keymap.h>
  259. X#endif /* SUN_4_0 */
  260. X
  261. Xextern Panel hdr_panel;
  262. Xextern void hdr_io(), fkey_interposer();
  263. X
  264. Xstatic Notify_value scroll_hdr();
  265. Xstatic void msg_menu_func(), do_menu(), msg_menu_notify();
  266. Xstatic Menu msg_menu;
  267. Xstatic Menu_item cur_msg_item;
  268. X
  269. Xvoid
  270. Xmake_hdr_sw(parent)
  271. XFrame parent;
  272. X{
  273. X    Textsw tmpsw;
  274. X
  275. X    if (!(hdr_sw = window_create(parent, CANVAS,
  276. X    WIN_HEIGHT,        10 + screen*l_height(),
  277. X    WIN_WIDTH,        WIN_EXTEND_TO_EDGE,
  278. X    WIN_BELOW,        hdr_panel,
  279. X    WIN_EVENT_PROC,        hdr_io,
  280. X    CANVAS_AUTO_CLEAR,    TRUE,
  281. X    CANVAS_RETAINED,    TRUE,
  282. X    WIN_CONSUME_KBD_EVENTS,
  283. X        WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  284. X    WIN_IGNORE_KBD_EVENTS,
  285. X        WIN_UP_ASCII_EVENTS, NULL,
  286. X    WIN_CONSUME_PICK_EVENTS,
  287. X        LOC_WINENTER, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
  288. X    WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
  289. X    NULL)))
  290. X    perror("hdr_sw"), cleanup(0);
  291. X    hdr_win = canvas_pixwin(hdr_sw);
  292. X    (void) notify_interpose_event_func(hdr_sw, fkey_interposer, NOTIFY_SAFE);
  293. X    (void) notify_interpose_event_func(hdr_sw, scroll_hdr, NOTIFY_SAFE);
  294. X    scrollbar_set((Scrollbar)window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR),
  295. X    SCROLL_NORMALIZE,    FALSE,
  296. X    SCROLL_ADVANCED_MODE,    TRUE,
  297. X    SCROLL_LINE_HEIGHT,    l_height(),
  298. X    SCROLL_VIEW_LENGTH,    screen,
  299. X    NULL);
  300. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  301. X    /* This is a particularly ugly hack.  If Sun only documented the correct
  302. X     * way to set up the key mapping for a window the way that textsw's do
  303. X     * then we wouldn't have to do anything this awful.  Maybe in 4.2.....
  304. X     *
  305. X     * The object here is to get the same translation table for our header
  306. X     * canvas as for a textsw (more or less anyway).  This way the arrow
  307. X     * keys and such work right.
  308. X     */
  309. X    tmpsw = window_create(parent, TEXTSW, NULL);
  310. X#ifdef SUN_4_1
  311. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].keymap =
  312. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap;
  313. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap = (Keymap *) 0;
  314. X#else /* !SUN_4_1 */
  315. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].kf_keymap =
  316. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap;
  317. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap = (Keymap *) 0;
  318. X#endif /* SUN_4_1 */
  319. X    (void) window_destroy(tmpsw);
  320. X#endif /* SUN_4_0 */
  321. X}
  322. X
  323. Xstatic Notify_value
  324. Xscroll_hdr(canvas, event, arg, type)
  325. XCanvas    canvas;
  326. XEvent    *event;
  327. XNotify_arg    arg;
  328. XNotify_event_type    type;
  329. X{
  330. X    int amount, count, i;
  331. X    int show_deleted = !!do_set(set_options, "show_deleted");
  332. X    char *argv[3], msgnum[8];
  333. X    Scrollbar sb;
  334. X    argv[0] = "headers";
  335. X    argv[1] = msgnum;
  336. X    argv[2] = NULL;
  337. X
  338. X    switch (decode_scroll((Notify_client) canvas, event, screen, &amount)) {
  339. X    case MUSH_SCROLL_PASS_EVENT:
  340. X        switch(ID) {
  341. X        case SCROLL_ENTER:
  342. X        case SCROLL_EXIT:
  343. X            return NOTIFY_IGNORED;
  344. X        case SCROLL_REQUEST:
  345. X            sb = (Scrollbar)arg;
  346. X            switch( (Scroll_motion)
  347. X             scrollbar_get(sb, SCROLL_REQUEST_MOTION)) {
  348. X            case SCROLL_LINE_FORWARD:
  349. X                amount = 1;
  350. X                break;
  351. X            case SCROLL_LINE_BACKWARD:
  352. X                amount = -1;
  353. X                break;
  354. X            case SCROLL_ABSOLUTE:
  355. X                i = (int)scrollbar_get(sb, SCROLL_VIEW_START);
  356. X                if (!show_deleted) {
  357. X                count = i;
  358. X                for (i = 0; i < msg_cnt-1; i++)
  359. X                        if (!ison(msg[i].m_flags, DELETE) &&
  360. X                        count-- == 0)
  361. X                    break;
  362. X                }
  363. X                (void) sprintf(msgnum, "%d", i+1);
  364. X                argv[1] = msgnum;
  365. X                (void) do_hdrs(2, argv, NULL);
  366. X                return(NOTIFY_DONE);
  367. X            default:
  368. X                amount =
  369. X                (int)scrollbar_get(sb, SCROLL_VIEW_START) -
  370. X                (int)scrollbar_get(sb, SCROLL_LAST_VIEW_START);
  371. X                break;
  372. X            }
  373. X            break;
  374. X        default:
  375. X            return notify_next_event_func(canvas, event, arg, type);
  376. X        }
  377. X        break;
  378. X    case MUSH_SCROLL_IGNORE:
  379. X        return NOTIFY_IGNORED;
  380. X    case MUSH_SCROLL_TO:
  381. X        if (amount == 1) {
  382. X        argv[1] = "1";
  383. X        (void) do_hdrs(2, argv, NULL);
  384. X        return NOTIFY_DONE;
  385. X        } else {
  386. X        (void) sprintf(msgnum, "%d", msg_cnt - screen + 1);
  387. X        argv[1] = msgnum;
  388. X        (void) do_hdrs(2, argv, NULL);
  389. X        return NOTIFY_DONE;
  390. X        }
  391. X    }
  392. X    if (amount == screen)
  393. X    argv[1] = "+";
  394. X    else if (amount == -screen)
  395. X    argv[1] = "-";
  396. X    else if (amount >= 0) {
  397. X    if (amount < screen)
  398. X        (void) sprintf(msgnum, "%d", min(n_array[amount]+1, msg_cnt-1));
  399. X    else {
  400. X        /* so much for layering */
  401. X        for (i = n_array[0]+1; i < msg_cnt-1 && amount > 0; i++)
  402. X        if (show_deleted || !ison(msg[i].m_flags, DELETE))
  403. X            amount--;
  404. X        (void) sprintf(msgnum, "%d", i);
  405. X    }
  406. X    } else {
  407. X    /* so much for layering */
  408. X    for (i = n_array[0]; i > 0 && amount < 0; i--)
  409. X        if (show_deleted || !ison(msg[i-1].m_flags, DELETE))
  410. X        amount++;
  411. X    (void) sprintf(msgnum, "%d", i + 1);
  412. X    }
  413. X    (void) do_hdrs(2, argv, NULL);
  414. X    return NOTIFY_DONE;
  415. X}
  416. X
  417. X/*
  418. X * Routines to handle io on the hdr_sw (canvas).
  419. X */
  420. X
  421. X/* if MENU button goes down on a hdr, drawbox around hdr and popup menu */
  422. X#define draw(x1,y1,x2,y2) (void) pw_vector(hdr_win, x1,y1,x2,y2,PIX_XOR,1)
  423. X#define box(x1,y1,x2,y2)  \
  424. X    draw(x1,y1, x1,y2), draw(x1,y2, x2,y2), \
  425. X    draw(x2,y2, x2,y1), draw(x2,y1, x1,y1)
  426. X
  427. X#define READ_MSG    (char *)'r'
  428. X#define DEL_MSG        (char *)'d'
  429. X#define UNDEL_MSG    (char *)'u'
  430. X#define REPL_MSG    (char *)'R'
  431. X#define SAVE_MSG    (char *)'s'
  432. X#define PRNT_MSG    (char *)'p'
  433. X#define PRE_MSG        (char *)'P'
  434. X#define HELP_MSG    (char *)'H'
  435. X
  436. X/*ARGSUSED*/
  437. Xvoid
  438. Xhdr_io(canvas, event, arg)
  439. XCanvas canvas;
  440. XEvent *event;
  441. Xcaddr_t arg;
  442. X{
  443. X    static int    which_cursor;
  444. X    int     line;
  445. X
  446. X    if (ID == WIN_REPAINT) {
  447. X    if (is_iconic != (int) window_get(tool, FRAME_CLOSED)) {
  448. X        check_new_mail();
  449. X
  450. X        /*  Reload time with value of timeout upon timer expiration. */
  451. X        mail_timer.it_interval.tv_sec = time_out;
  452. X
  453. X        mail_timer.it_value.tv_sec = time_out;
  454. X        (void) notify_set_itimer_func(tool, do_check,
  455. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  456. X        is_iconic = 0;
  457. X    }
  458. X    }
  459. X
  460. X    /* make cursor change which button is lit */
  461. X    switch (which_cursor) {
  462. X    case 0 : (void) window_set(canvas, WIN_CURSOR, l_cursor, NULL);
  463. X    when 1 : (void) window_set(canvas, WIN_CURSOR, m_cursor, NULL);
  464. X    when 2 : (void) window_set(canvas, WIN_CURSOR, r_cursor, NULL);
  465. X    }
  466. X
  467. X    which_cursor = (which_cursor+1) % 3;
  468. X
  469. X    /* just return -- we just wanted to make the cursor flicker */
  470. X    if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER ||
  471. X    ID == LOC_RGNENTER || ID == KBD_USE || ID == KBD_DONE)
  472. X    return;
  473. X
  474. X    if (event_is_button(event) && event_is_down(event)) {
  475. X    line = (event_y(event) - 5) / l_height();
  476. X    if (line < 0)
  477. X        line = 0;
  478. X    else if (line >= screen)
  479. X        line = screen - 1;
  480. X    if (!msg_cnt || n_array[line] > msg_cnt)
  481. X        return;
  482. X    if (ID == MS_RIGHT)
  483. X        do_menu(hdr_sw, event, window_get(hdr_sw, WIN_FD), n_array[line]);
  484. X    else if (ID == MS_MIDDLE) {
  485. X        set_isread(n_array[line]);
  486. X        msg_menu_func(DEL_MSG, n_array[line]);
  487. X    } else {
  488. X        int do_do_hdrs = 0;
  489. X        if (current_msg != n_array[line]) {
  490. X        current_msg = n_array[line];
  491. X        do_do_hdrs++;
  492. X        }
  493. X        if (ison(msg[current_msg].m_flags, UNREAD))
  494. X        do_do_hdrs++;
  495. X        (void) display_msg(n_array[line], (u_long)0);
  496. X        if (do_do_hdrs)
  497. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  498. X    }
  499. X    } else
  500. X    window_default_event_proc(canvas, event, NULL);
  501. X}
  502. X
  503. Xstatic struct menu_rec {
  504. X    char *str;    /* Menu item label. */
  505. X    char *data;    /* Menu item client data. */
  506. X};
  507. X
  508. Xstatic void
  509. Xget_msg_menu()
  510. X{
  511. X    int i;
  512. X    Menu_item mi = NULL;
  513. X
  514. X    static struct menu_rec msg_items[] = {
  515. X    { "Read",            READ_MSG  },
  516. X    { "Delete",          DEL_MSG   },
  517. X    { "Undelete",        UNDEL_MSG },
  518. X    { "Reply",           REPL_MSG  },
  519. X    { "Save",            SAVE_MSG  },
  520. X    { "Preserve",        PRE_MSG   },
  521. X    { "Print",           PRNT_MSG  },
  522. X    { "Help",            HELP_MSG  },
  523. X    };
  524. X
  525. X    msg_menu = menu_create(MENU_NOTIFY_PROC, msg_menu_notify, NULL);
  526. X    for (i = 0; i < ArraySize(msg_items); i++) {
  527. X    mi = menu_create_item(MENU_STRING,    msg_items[i].str,
  528. X                  MENU_CLIENT_DATA,    msg_items[i].data,
  529. X                  NULL);
  530. X    (void) menu_set(msg_menu, MENU_APPEND_ITEM, mi, NULL);
  531. X    }
  532. X}
  533. X
  534. Xstatic void
  535. Xmsg_menu_notify(menu, item)
  536. XMenu menu;
  537. XMenu_item item;
  538. X{
  539. X    cur_msg_item = item;
  540. X}
  541. X
  542. Xstatic void
  543. Xdo_menu(can_sw, event, fd, message)
  544. XCanvas can_sw;
  545. XEvent *event;
  546. Xint fd, message;
  547. X{
  548. X    char *action;
  549. X    static char buf[16];
  550. X
  551. X    if (!msg_cnt) {
  552. X    wprint("No Messages.\n");
  553. X    return;
  554. X    }
  555. X    if (fd) {
  556. X    int line;
  557. X    Rect *hdr_rect;
  558. X
  559. X    if (!msg_menu)
  560. X        get_msg_menu();
  561. X    (void) sprintf(buf, "Message #%d", message+1);
  562. X    /* provide feedback about what message the menu references */
  563. X    for (line = 0; line <= n_array[screen-1]; line++)
  564. X        if (n_array[line] == message)
  565. X        break;
  566. X    hdr_rect = (Rect *)window_get(hdr_sw, WIN_RECT);
  567. X    box(0, 5 + line * l_height(),
  568. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  569. X    /* show menu */
  570. X    menu_show(msg_menu, can_sw, event, NULL);
  571. X    /* remove feedback */
  572. X    box(0, 5 + line * l_height(),
  573. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  574. X    /* if user selected something, figure out what was selected. */
  575. X    if (!cur_msg_item)
  576. X        return;
  577. X    action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
  578. X    cur_msg_item = (Menu_item)NULL;
  579. X    } else
  580. X    action = (char *) event;
  581. X
  582. X    set_isread(message);
  583. X    switch ((int) action) {
  584. X    case SAVE_MSG : {
  585. X        extern Panel_item msg_num_item, save_item;
  586. X        (void) panel_set(msg_num_item, PANEL_VALUE,
  587. X                    sprintf(buf, "%d", message+1), NULL);
  588. X        event_id(event) = MS_LEFT;
  589. X        do_file_dir(save_item, 0, event);
  590. X        (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  591. X    }
  592. X    when HELP_MSG :
  593. X        help(0, "headers", tool_help);
  594. X    when PRNT_MSG : case PRE_MSG : case UNDEL_MSG : case DEL_MSG :
  595. X        msg_menu_func(action, message);
  596. X    when REPL_MSG : {
  597. X        extern Panel_item reply_item;
  598. X        (void) open_compose();
  599. X        /* reply_item shouldn't be here */
  600. X        respond_mail(reply_item, message, NO_EVENT);
  601. X    }
  602. X    otherwise :
  603. X        if (current_msg != message) {
  604. X        current_msg = message;
  605. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  606. X        }
  607. X#ifdef SUN_3_5
  608. X        /* Test for a shortage of file descriptors */
  609. X        if (nopenfiles(0) > 3)
  610. X#endif /* SUN_3_5 */
  611. X        turnon(glob_flags, NEW_FRAME);
  612. X        more_prompt = compose_hdr(message);
  613. X        display_msg(message, (u_long)0);
  614. X    }
  615. X}
  616. X
  617. X/* msg_menu_func() is a function called to perform message menu actions
  618. X * that are either selected from the popup menu in the header window or
  619. X * from mouse actions that function as accelerators.
  620. X */
  621. Xstatic void
  622. Xmsg_menu_func(action, message)
  623. Xchar *action;
  624. X{
  625. X    int argc;
  626. X    register char **argv;
  627. X    char buf[32];
  628. X
  629. X    wprint("Message #%d ", message+1);
  630. X    if (action == UNDEL_MSG || action == DEL_MSG)
  631. X    wprint("%sd.\n", sprintf(buf, "%selete",
  632. X                (action == DEL_MSG)? "d": "und"));
  633. X    else if (action == PRNT_MSG) {
  634. X    wprint("sent to printer.\n");
  635. X    (void) strcpy(buf, "lpr");
  636. X    } else if (action == PRE_MSG)
  637. X    wprint("%sd.\n", strcpy(buf, "preserve"));
  638. X    (void) sprintf(&buf[strlen(buf)], " %d", message+1);
  639. X
  640. X    if (argv = make_command(buf, (char ***) DUBL_NULL, &argc))
  641. X    (void) do_command(argc, argv, msg_list);
  642. X}
  643. END_OF_FILE
  644. if test 11559 -ne `wc -c <'mush/hdr_sw.c'`; then
  645.     echo shar: \"'mush/hdr_sw.c'\" unpacked with wrong size!
  646. fi
  647. # end of 'mush/hdr_sw.c'
  648. fi
  649. if test -f 'mush/malloc.c' -a "${1}" != "-c" ; then 
  650.   echo shar: Will not clobber existing file \"'mush/malloc.c'\"
  651. else
  652. echo shar: Extracting \"'mush/malloc.c'\" \(10827 characters\)
  653. sed "s/^X//" >'mush/malloc.c' <<'END_OF_FILE'
  654. X/*
  655. X * This is a slightly modified version of the malloc.c distributed with
  656. X * Larry Wall's perl 2.0 sources.  RCS and sccs information has been
  657. X * retained, but modified so that it will not actually affect checkin
  658. X * or checkout of this file if revision control is used for Mush.
  659. X *
  660. X * Other changes include:
  661. X *    Removal of the ASSERT macro and other code related to the
  662. X *    preprocessor definition "debug"
  663. X *
  664. X *    Replaced #include "perl.h" with #include "mush.h" (guess why)
  665. X *
  666. X *    Warning messages are now printed with the mush Debug macro,
  667. X *    that is, they are normally suppressed
  668. X *
  669. X *    Added a calloc() function, using mush's bzero()
  670. X *
  671. X * Also, the mush xfree() and free_vec() functions have been moved here.
  672. X */
  673. X
  674. X#include "mush.h"
  675. X
  676. X/*
  677. X * Compile this portion only if configured for INTERNAL_MALLOC
  678. X */
  679. X#ifdef INTERNAL_MALLOC
  680. X#ifdef SYSV
  681. X#include <memory.h>
  682. X#define bcopy(src,dst,len)    memcpy(dst,src,len)
  683. X#endif /* SYSV */
  684. X#define free xfree    /* rename free for mush purposes */
  685. X
  686. X/* Begin modified perl malloc.c */
  687. X
  688. X/* Header: malloc.c,v 2.0 88/06/05 00:09:16 root Exp
  689. X *
  690. X * Log:    malloc.c,v
  691. X * Revision 2.0  88/06/05  00:09:16  root
  692. X * Baseline version 2.0.
  693. X * 
  694. X */
  695. X
  696. X#ifndef lint
  697. Xstatic char sccsid[] = "malloc.c    4.3 (Berkeley) 9/16/83";
  698. X#endif /* !lint */
  699. X
  700. X#define RCHECK
  701. X/*
  702. X * malloc.c (Caltech) 2/21/82
  703. X * Chris Kingsley, kingsley@cit-20.
  704. X *
  705. X * This is a very fast storage allocator.  It allocates blocks of a small 
  706. X * number of different sizes, and keeps free lists of each size.  Blocks that
  707. X * don't exactly fit are passed up to the next larger size.  In this 
  708. X * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
  709. X * This is designed for use in a program that uses vast quantities of memory,
  710. X * but bombs when it runs out. 
  711. X */
  712. X
  713. X/* I don't much care whether these are defined in sys/types.h--LAW */
  714. X
  715. X#undef u_char
  716. X#define u_char unsigned char
  717. X#undef u_int
  718. X#define u_int unsigned int
  719. X#undef u_short
  720. X#define u_short unsigned short
  721. X
  722. X/*
  723. X * The overhead on a block is at least 4 bytes.  When free, this space
  724. X * contains a pointer to the next free block, and the bottom two bits must
  725. X * be zero.  When in use, the first byte is set to MAGIC, and the second
  726. X * byte is the size index.  The remaining bytes are for alignment.
  727. X * If range checking is enabled and the size of the block fits
  728. X * in two bytes, then the top two bytes hold the size of the requested block
  729. X * plus the range checking words, and the header word MINUS ONE.
  730. X */
  731. Xunion    overhead {
  732. X    union    overhead *ov_next;    /* when free */
  733. X    struct {
  734. X        u_char    ovu_magic;    /* magic number */
  735. X        u_char    ovu_index;    /* bucket # */
  736. X#ifdef RCHECK
  737. X        u_short    ovu_size;    /* actual block size */
  738. X        u_int    ovu_rmagic;    /* range magic number */
  739. X#endif /* RCHECK */
  740. X    } ovu;
  741. X#define    ov_magic    ovu.ovu_magic
  742. X#define    ov_index    ovu.ovu_index
  743. X#define    ov_size        ovu.ovu_size
  744. X#define    ov_rmagic    ovu.ovu_rmagic
  745. X};
  746. X
  747. X#define    MAGIC        0xff        /* magic # on accounting info */
  748. X#define OLDMAGIC    0x7f        /* same after a free() */
  749. X#define RMAGIC        0x55555555    /* magic # on range info */
  750. X#ifdef RCHECK
  751. X#define    RSLOP        sizeof (u_int)
  752. X#else /* !RCHECK */
  753. X#define    RSLOP        0
  754. X#endif /* RCHECK */
  755. X
  756. X/*
  757. X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  758. X * smallest allocatable block is 8 bytes.  The overhead information
  759. X * precedes the data area returned to the user.
  760. X */
  761. X#define    NBUCKETS 30
  762. Xstatic    union overhead *nextf[NBUCKETS];
  763. Xextern    char *sbrk();
  764. X
  765. X#ifdef MSTATS
  766. X/*
  767. X * nmalloc[i] is the difference between the number of mallocs and frees
  768. X * for a given block size.
  769. X */
  770. Xstatic    u_int nmalloc[NBUCKETS];
  771. X#endif /* MSTATS */
  772. X
  773. Xchar *
  774. Xmalloc(nbytes)
  775. X    register unsigned nbytes;
  776. X{
  777. X    register union overhead *p;
  778. X    register int bucket = 0;
  779. X    register unsigned shiftr;
  780. X
  781. X    /*
  782. X     * Convert amount of memory requested into
  783. X     * closest block size stored in hash buckets
  784. X     * which satisfies request.  Account for
  785. X     * space used per block for accounting.
  786. X     */
  787. X    nbytes += sizeof (union overhead) + RSLOP;
  788. X    nbytes = (nbytes + 3) &~ 3; 
  789. X    shiftr = (nbytes - 1) >> 2;
  790. X    /* apart from this loop, this is O(1) */
  791. X    while (shiftr >>= 1)
  792. X        bucket++;
  793. X    /*
  794. X     * If nothing in hash bucket right now,
  795. X     * request more memory from the system.
  796. X     */
  797. X    if (nextf[bucket] == (union overhead *)0)    
  798. X        morecore(bucket);
  799. X    if ((p = (union overhead *)nextf[bucket]) == (union overhead *)0)
  800. X        return (NULL);
  801. X    /* remove from linked list */
  802. X    if (*((int*)p) > 0x10000000)
  803. X        Debug("Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
  804. X    nextf[bucket] = nextf[bucket]->ov_next;
  805. X    p->ov_magic = MAGIC;
  806. X    p->ov_index= bucket;
  807. X#ifdef MSTATS
  808. X    nmalloc[bucket]++;
  809. X#endif /* MSTATS */
  810. X#ifdef RCHECK
  811. X    /*
  812. X     * Record allocated size of block and
  813. X     * bound space with magic numbers.
  814. X     */
  815. X    if (nbytes <= 0x10000)
  816. X        p->ov_size = nbytes - 1;
  817. X    p->ov_rmagic = RMAGIC;
  818. X    *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
  819. X#endif /* RCHECK */
  820. X    return ((char *)(p + 1));
  821. X}
  822. X
  823. X/*
  824. X * Allocate more memory to the indicated bucket.
  825. X */
  826. Xstatic
  827. Xmorecore(bucket)
  828. X    register bucket;
  829. X{
  830. X    register union overhead *op;
  831. X    register int rnu;       /* 2^rnu bytes will be requested */
  832. X    register int nblks;     /* become nblks blocks of the desired size */
  833. X    register int siz;
  834. X
  835. X    if (nextf[bucket])
  836. X        return;
  837. X    /*
  838. X     * Insure memory is allocated
  839. X     * on a page boundary.  Should
  840. X     * make getpageize call?
  841. X     */
  842. X    op = (union overhead *)sbrk(0);
  843. X    if ((long)op & 0x3ff)
  844. X        sbrk(1024 - ((long)op & 0x3ff));
  845. X    /* take 2k unless the block is bigger than that */
  846. X    rnu = (bucket <= 8) ? 11 : bucket + 3;
  847. X    nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
  848. X    if (rnu < bucket)
  849. X        rnu = bucket;
  850. X    op = (union overhead *)sbrk(1 << rnu);
  851. X    /* no more room! */
  852. X    if ((long)op == -1)
  853. X        return;
  854. X    /*
  855. X     * Round up to minimum allocation size boundary
  856. X     * and deduct from block count to reflect.
  857. X     */
  858. X    if ((long)op & 7) {
  859. X        op = (union overhead *)(((long)op + 8) &~ 7);
  860. X        nblks--;
  861. X    }
  862. X    /*
  863. X     * Add new memory allocated to that on
  864. X     * free list for this hash bucket.
  865. X     */
  866. X    nextf[bucket] = op;
  867. X    siz = 1 << (bucket + 3);
  868. X    while (--nblks > 0) {
  869. X        op->ov_next = (union overhead *)((caddr_t)op + siz);
  870. X        op = (union overhead *)((caddr_t)op + siz);
  871. X    }
  872. X}
  873. X
  874. Xvoid
  875. Xfree(cp)
  876. X    char *cp;
  877. X{   
  878. X    register int size;
  879. X    register union overhead *op;
  880. X
  881. X    if (cp == NULL || debug < 5)
  882. X        return;
  883. X    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  884. X    if (op->ov_magic != MAGIC) {
  885. X        Debug("%s free() ignored\n",
  886. X            op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
  887. X        return;                /* sanity */
  888. X    }
  889. X    op->ov_magic = OLDMAGIC;
  890. X#ifdef RCHECK
  891. X    if (op->ov_rmagic != RMAGIC) {
  892. X        Debug("Range check failed, free() ignored\n");
  893. X        return;
  894. X    }
  895. X    if (op->ov_index <= 13 &&
  896. X        *(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) != RMAGIC) {
  897. X        Debug("Range check failed, free() ignored\n");
  898. X        return;
  899. X    }
  900. X#endif /* RCHECK */
  901. X    if (op->ov_index >= NBUCKETS)
  902. X        return;
  903. X    size = op->ov_index;
  904. X    op->ov_next = nextf[size];
  905. X    nextf[size] = op;
  906. X#ifdef MSTATS
  907. X    nmalloc[size]--;
  908. X#endif /* MSTATS */
  909. X}
  910. X
  911. X/*
  912. X * When a program attempts "storage compaction" as mentioned in the
  913. X * old malloc man page, it realloc's an already freed block.  Usually
  914. X * this is the last block it freed; occasionally it might be farther
  915. X * back.  We have to search all the free lists for the block in order
  916. X * to determine its bucket: 1st we make one pass thru the lists
  917. X * checking only the first block in each; if that fails we search
  918. X * ``reall_srchlen'' blocks in each list for a match (the variable
  919. X * is extern so the caller can modify it).  If that fails we just copy
  920. X * however many bytes was given to realloc() and hope it's not huge.
  921. X */
  922. Xint reall_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  923. X
  924. Xchar *
  925. Xrealloc(cp, nbytes)
  926. X    char *cp; 
  927. X    unsigned nbytes;
  928. X{   
  929. X    register u_int onb;
  930. X    union overhead *op;
  931. X    char *res;
  932. X    register int i;
  933. X    int was_alloced = 0;
  934. X
  935. X    if (cp == NULL)
  936. X        return (malloc(nbytes));
  937. X    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  938. X    if (op->ov_magic == MAGIC) {
  939. X        was_alloced++;
  940. X        i = op->ov_index;
  941. X    } else {
  942. X        /*
  943. X         * Already free, doing "compaction".
  944. X         *
  945. X         * Search for the old block of memory on the
  946. X         * free list.  First, check the most common
  947. X         * case (last element free'd), then (this failing)
  948. X         * the last ``reall_srchlen'' items free'd.
  949. X         * If all lookups fail, then assume the size of
  950. X         * the memory block being realloc'd is the
  951. X         * smallest possible.
  952. X         */
  953. X        if ((i = findbucket(op, 1)) < 0 &&
  954. X            (i = findbucket(op, reall_srchlen)) < 0)
  955. X            i = 0;
  956. X    }
  957. X    onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
  958. X    /* avoid the copy if same size block */
  959. X    if (was_alloced &&
  960. X        nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
  961. X        return(cp);
  962. X    if ((res = malloc(nbytes)) == NULL)
  963. X        return (NULL);
  964. X    if (cp != res)            /* common optimization */
  965. X        bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
  966. X    if (was_alloced)
  967. X        free(cp);
  968. X    return (res);
  969. X}
  970. X
  971. X/*
  972. X * Search ``srchlen'' elements of each free list for a block whose
  973. X * header starts at ``freep''.  If srchlen is -1 search the whole list.
  974. X * Return bucket number, or -1 if not found.
  975. X */
  976. Xstatic
  977. Xfindbucket(freep, srchlen)
  978. X    union overhead *freep;
  979. X    int srchlen;
  980. X{
  981. X    register union overhead *p;
  982. X    register int i, j;
  983. X
  984. X    for (i = 0; i < NBUCKETS; i++) {
  985. X        j = 0;
  986. X        for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
  987. X            if (p == freep)
  988. X                return (i);
  989. X            j++;
  990. X        }
  991. X    }
  992. X    return (-1);
  993. X}
  994. X
  995. X#ifdef MSTATS
  996. X/*
  997. X * mstats - print out statistics about malloc
  998. X * 
  999. X * Prints two lines of numbers, one showing the length of the free list
  1000. X * for each size category, the second showing the number of mallocs -
  1001. X * frees for each size category.
  1002. X */
  1003. Xmstats(s)
  1004. X    char *s;
  1005. X{
  1006. X    register int i, j;
  1007. X    register union overhead *p;
  1008. X    int totfree = 0,
  1009. X    totused = 0;
  1010. X
  1011. X    Debug("Memory allocation statistics %s\nfree:\t", s);
  1012. X    for (i = 0; i < NBUCKETS; i++) {
  1013. X        for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  1014. X            ;
  1015. X        Debug(" %d", j);
  1016. X        totfree += j * (1 << (i + 3));
  1017. X    }
  1018. X    Debug("\nused:\t");
  1019. X    for (i = 0; i < NBUCKETS; i++) {
  1020. X        Debug( " %d", nmalloc[i]);
  1021. X        totused += nmalloc[i] * (1 << (i + 3));
  1022. X    }
  1023. X    Debug("\n\tTotal in use: %d, total free: %d\n",
  1024. X        totused, totfree);
  1025. X}
  1026. X#endif /* MSTATS */
  1027. X
  1028. X/* End of modified perl malloc.c */
  1029. X
  1030. Xchar *
  1031. Xcalloc(nitems, itemsz)
  1032. Xu_int nitems, itemsz;
  1033. X{
  1034. X    char *cp;
  1035. X
  1036. X    cp = malloc(nitems * itemsz);
  1037. X    bzero(cp, nitems * itemsz);
  1038. X    return cp;
  1039. X}
  1040. X
  1041. X/* These are needed for curses and other external linkage */
  1042. X
  1043. X#undef free
  1044. X
  1045. Xchar *
  1046. Xcfree(p, n, s)
  1047. Xchar *p;
  1048. Xu_int n, s;
  1049. X{
  1050. X    xfree(p);
  1051. X    return NULL;
  1052. X}
  1053. X
  1054. Xchar *
  1055. Xfree(p)
  1056. Xchar *p;
  1057. X{
  1058. X    xfree(p);
  1059. X    return NULL;
  1060. X}
  1061. X
  1062. X#else /* INTERNAL_MALLOC */
  1063. X
  1064. Xchar *stackbottom;    /* set first thing in main() */
  1065. X
  1066. Xvoid
  1067. Xxfree(cp)
  1068. Xchar *cp;
  1069. X{
  1070. X    extern char end[];
  1071. X
  1072. X    if (cp >= end && cp < stackbottom && cp < (char *) &cp && debug < 5)
  1073. X    free(cp);
  1074. X}
  1075. X
  1076. X#endif /* INTERNAL_MALLOC */
  1077. X
  1078. Xvoid
  1079. Xfree_vec(argv)
  1080. Xchar **argv;
  1081. X{
  1082. X    register int n;
  1083. X    if (!argv)
  1084. X    return;
  1085. X    for (n = 0; argv[n]; n++)
  1086. X    xfree(argv[n]);
  1087. X    xfree((char *)argv);
  1088. X}
  1089. END_OF_FILE
  1090. if test 10827 -ne `wc -c <'mush/malloc.c'`; then
  1091.     echo shar: \"'mush/malloc.c'\" unpacked with wrong size!
  1092. fi
  1093. # end of 'mush/malloc.c'
  1094. fi
  1095. if test -f 'mush/misc_frame.c' -a "${1}" != "-c" ; then 
  1096.   echo shar: Will not clobber existing file \"'mush/misc_frame.c'\"
  1097. else
  1098. echo shar: Extracting \"'mush/misc_frame.c'\" \(7659 characters\)
  1099. sed "s/^X//" >'mush/misc_frame.c' <<'END_OF_FILE'
  1100. X/* @(#) misc_frame.c    (c) copyright    9/29/89 (Dan Heller) */
  1101. X
  1102. X/*
  1103. X * This file contains several functions which create dialog box frames
  1104. X * for (currently) mail aliases and ignored headers.  Each dialog box
  1105. X * has a list of some kind and a way to add or delete items from the
  1106. X * list.  The list is a textsw which is updated (currently) by do_set().
  1107. X * Public routines:
  1108. X *    update_list_textsw(struct options **) updates the textsw list.
  1109. X *    do_alias()    creates the alias dialog frame box
  1110. X *    do_ignore()    creates the ignored headers dialog frame box
  1111. X */
  1112. X
  1113. X#include "mush.h"
  1114. X
  1115. Xextern Notify_value fkey_interposer();
  1116. X
  1117. X/****************** Mail Aliases ********************/
  1118. X
  1119. XFrame    alias_frame;
  1120. XPanel_item alias_msg, alias_name, alias_value, alias_list_textsw;
  1121. Xstatic void set_alias();
  1122. X
  1123. XFrame    ignore_frame;
  1124. XPanel_item ignore_msg, ignore_name, ignore_list_textsw;
  1125. Xstatic Panel_setting set_ignore();
  1126. X
  1127. X#define MY_FRAME_WIDTH    600
  1128. X
  1129. Xstatic void
  1130. Xframe_help(item)
  1131. XPanel_item item;
  1132. X{
  1133. X    (void) help(0, panel_get(item, PANEL_CLIENT_DATA), tool_help);
  1134. X}
  1135. X
  1136. Xvoid
  1137. Xupdate_list_textsw(list)
  1138. Xstruct options **list;
  1139. X{
  1140. X    Textsw save = pager_textsw;
  1141. X
  1142. X    if (list == &aliases)
  1143. X    pager_textsw = alias_list_textsw;
  1144. X    else if (list == &ignore_hdr)
  1145. X    pager_textsw = ignore_list_textsw;
  1146. X    else
  1147. X    /* no textsw for this guy yet */
  1148. X    return;
  1149. X
  1150. X    if (pager_textsw && !!window_get(pager_textsw, WIN_SHOW))
  1151. X    (void) do_set(*list, NULL);
  1152. X    pager_textsw = save;
  1153. X}
  1154. X
  1155. Xstatic void
  1156. Xalias_done()
  1157. X{
  1158. X    window_destroy(alias_frame);
  1159. X    alias_frame = (Frame) 0;
  1160. X}
  1161. X
  1162. Xvoid
  1163. Xdo_aliases()
  1164. X{
  1165. X    Panel    panel;
  1166. X
  1167. X    if (alias_frame) {
  1168. X    window_set(alias_frame, WIN_SHOW, TRUE, NULL);
  1169. X    return;
  1170. X    }
  1171. X#ifdef SUN_3_5
  1172. X    if (nopenfiles(0) < 5) {
  1173. X    print("Too many frames; close one first!\n");
  1174. X    return;
  1175. X    }
  1176. X#endif /* SUN_3_5 */
  1177. X
  1178. X    alias_frame = window_create(tool, FRAME,
  1179. X    FRAME_SHOW_LABEL,    TRUE,
  1180. X    FRAME_LABEL,        "Mail Aliases",
  1181. X    FRAME_NO_CONFIRM,    TRUE,
  1182. X    FRAME_DONE_PROC,    alias_done,
  1183. X    WIN_SHOW,        TRUE,
  1184. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1185. X    NULL);
  1186. X
  1187. X    panel = window_create(alias_frame, PANEL,
  1188. X    PANEL_WIDTH,        MY_FRAME_WIDTH,
  1189. X    NULL);
  1190. X    notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1191. X
  1192. X    panel_create_item(panel, PANEL_BUTTON,
  1193. X    PANEL_LABEL_IMAGE,
  1194. X        panel_button_image(panel, "Help", 4, mush_font),
  1195. X    PANEL_CLIENT_DATA,    "aliases",
  1196. X    PANEL_NOTIFY_PROC,    frame_help,
  1197. X    NULL);
  1198. X    panel_create_item(panel, PANEL_BUTTON,
  1199. X    PANEL_LABEL_IMAGE,
  1200. X        panel_button_image(panel, "Set", 3, mush_font),
  1201. X    PANEL_NOTIFY_PROC,    set_alias,
  1202. X    PANEL_CLIENT_DATA,    TRUE,
  1203. X    NULL);
  1204. X    panel_create_item(panel, PANEL_BUTTON,
  1205. X    PANEL_LABEL_IMAGE,
  1206. X        panel_button_image(panel, "Unset", 5, mush_font),
  1207. X    PANEL_NOTIFY_PROC,    set_alias,
  1208. X    PANEL_CLIENT_DATA,    FALSE,
  1209. X    NULL);
  1210. X
  1211. X    alias_msg = panel_create_item(panel, PANEL_MESSAGE,
  1212. X    PANEL_LABEL_STRING,
  1213. X        "Type name of alias and address list and select <set> or <unset>",
  1214. X    NULL);
  1215. X
  1216. X    alias_name = panel_create_item(panel, PANEL_TEXT,
  1217. X    PANEL_LABEL_STRING,    "Alias Name:",
  1218. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1219. X    NULL);
  1220. X    alias_value = panel_create_item(panel, PANEL_TEXT,
  1221. X    PANEL_LABEL_STRING,    "Alias Address(es):",
  1222. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1223. X    NULL);
  1224. X    window_fit_height(panel);
  1225. X
  1226. X    alias_list_textsw = window_create(alias_frame, TEXTSW,
  1227. X    WIN_BELOW,            panel,
  1228. X    WIN_WIDTH,            MY_FRAME_WIDTH,
  1229. X    WIN_HEIGHT,            15 * l_height(),
  1230. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  1231. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_WORD,
  1232. X#else /* SUN_4_0 */
  1233. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  1234. X#endif /* SUN_4_0 */
  1235. X    NULL);
  1236. X    (void) notify_interpose_event_func(alias_list_textsw,
  1237. X    fkey_interposer, NOTIFY_SAFE);
  1238. X
  1239. X    window_fit_height(alias_frame);
  1240. X    update_list_textsw(&aliases);
  1241. X}
  1242. X
  1243. Xstatic void
  1244. Xset_alias(item)
  1245. XPanel_item item;
  1246. X{
  1247. X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
  1248. X    char buf[BUFSIZ], **argv, *name, *value;
  1249. X
  1250. X    name = panel_get_value(alias_name);
  1251. X    if (!*name) {
  1252. X    panel_set(alias_msg, PANEL_LABEL_STRING, "Need an alias name.", NULL);
  1253. X    return;
  1254. X    }
  1255. X    if (any(name, " \t")) {
  1256. X    panel_set(alias_msg,
  1257. X        PANEL_LABEL_STRING, "Alias name may not contain spaces.",
  1258. X        NULL);
  1259. X    return;
  1260. X    }
  1261. X    if (set_it) {
  1262. X    value = panel_get_value(alias_value);
  1263. X    if (!*value) {
  1264. X        panel_set(alias_msg,
  1265. X        PANEL_LABEL_STRING, "Specify alias address(es).",
  1266. X        NULL);
  1267. X        return;
  1268. X    }
  1269. X    sprintf(buf, "alias %s %s", name, value);
  1270. X    } else
  1271. X    sprintf(buf, "unalias %s", name);
  1272. X    if (!(argv = mk_argv(buf, &argc, TRUE)) || do_alias(argc, argv) == -1)
  1273. X    panel_set(alias_msg,
  1274. X        PANEL_LABEL_STRING, "Couldn't set alias.",
  1275. X        NULL);
  1276. X    else
  1277. X    panel_set(alias_msg,
  1278. X        PANEL_LABEL_STRING, "",
  1279. X        NULL);
  1280. X    panel_set_value(alias_name, "");
  1281. X    panel_set_value(alias_value, "");
  1282. X    free_vec(argv);
  1283. X}
  1284. X
  1285. X/* int cuz it's also the callback for the text item */
  1286. Xstatic Panel_setting
  1287. Xset_ignore(item)
  1288. XPanel_item item;
  1289. X{
  1290. X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
  1291. X    char buf[BUFSIZ], *name, **argv;
  1292. X
  1293. X    name = panel_get_value(ignore_name);
  1294. X    if (!*name) {
  1295. X    panel_set(ignore_msg, PANEL_LABEL_STRING, "Missing header name.", NULL);
  1296. X    return PANEL_NONE;
  1297. X    }
  1298. X    if (set_it)
  1299. X    sprintf(buf, "ignore %s", name);
  1300. X    else
  1301. X    sprintf(buf, "unignore %s", name);
  1302. X    /* set() will call update_list_textsw() */
  1303. X    if (!(argv = mk_argv(buf, &argc, TRUE)) || set(argc, argv, NULL) == -1)
  1304. X    panel_set(ignore_msg,
  1305. X        PANEL_LABEL_STRING, "Internal Error!?",
  1306. X        NULL);
  1307. X    else
  1308. X    panel_set(ignore_msg,
  1309. X        PANEL_LABEL_STRING, "",
  1310. X        NULL);
  1311. X    free_vec(argv);
  1312. X    panel_set_value(ignore_name, "");
  1313. X    return PANEL_NONE;
  1314. X}
  1315. X
  1316. Xstatic void
  1317. Xignore_done()
  1318. X{
  1319. X    window_destroy(ignore_frame);
  1320. X    ignore_frame = (Frame) 0;
  1321. X}
  1322. X
  1323. Xvoid
  1324. Xdo_ignore()
  1325. X{
  1326. X    Panel    panel;
  1327. X
  1328. X    if (ignore_frame) {
  1329. X    window_set(ignore_frame, WIN_SHOW, TRUE, NULL);
  1330. X    return;
  1331. X    }
  1332. X#ifdef SUN_3_5
  1333. X    if (nopenfiles(0) < 5) {
  1334. X    print("Too many frames; close one first!\n");
  1335. X    return;
  1336. X    }
  1337. X#endif /* SUN_3_5 */
  1338. X
  1339. X    ignore_frame = window_create(tool, FRAME,
  1340. X    FRAME_SHOW_LABEL,    TRUE,
  1341. X    FRAME_LABEL,        "Ignored Headers",
  1342. X    FRAME_NO_CONFIRM,    TRUE,
  1343. X    FRAME_DONE_PROC,    ignore_done,
  1344. X    WIN_SHOW,        TRUE,
  1345. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1346. X    NULL);
  1347. X
  1348. X    panel = window_create(ignore_frame, PANEL,
  1349. X    PANEL_WIDTH,        MY_FRAME_WIDTH,
  1350. X    NULL);
  1351. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1352. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1353. X    PANEL_LABEL_IMAGE,    
  1354. X        panel_button_image(panel, "Help", 4, mush_font),
  1355. X    PANEL_NOTIFY_PROC,    frame_help,
  1356. X    PANEL_CLIENT_DATA,    "ignore",
  1357. X    NULL);
  1358. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1359. X    PANEL_LABEL_IMAGE,    
  1360. X        panel_button_image(panel, "Set", 3, mush_font),
  1361. X    PANEL_NOTIFY_PROC,    set_ignore,
  1362. X    PANEL_CLIENT_DATA,    TRUE,
  1363. X    NULL);
  1364. X    panel_create_item(panel, PANEL_BUTTON,
  1365. X    PANEL_LABEL_IMAGE,    
  1366. X        panel_button_image(panel, "Unset", 5, mush_font),
  1367. X    PANEL_NOTIFY_PROC,    set_ignore,
  1368. X    PANEL_CLIENT_DATA,    FALSE,
  1369. X    NULL);
  1370. X
  1371. X    ignore_msg = panel_create_item(panel, PANEL_MESSAGE,
  1372. X    PANEL_LABEL_STRING,
  1373. X        "Type name of header to ignore and then <set> or <unset>",
  1374. X    NULL);
  1375. X
  1376. X    ignore_name = panel_create_item(panel, PANEL_TEXT,
  1377. X    PANEL_LABEL_STRING,    "Ignored Header:",
  1378. X    PANEL_NOTIFY_PROC,    set_ignore,
  1379. X    PANEL_CLIENT_DATA,    1,
  1380. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1381. X    NULL);
  1382. X    window_fit_height(panel);
  1383. X
  1384. X    ignore_list_textsw = window_create(ignore_frame, TEXTSW,
  1385. X    WIN_BELOW,        panel,
  1386. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1387. X    WIN_HEIGHT,        15 * l_height(),
  1388. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  1389. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_WORD,
  1390. X#else /* SUN_4_0 */
  1391. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  1392. X#endif /* SUN_4_0 */
  1393. X    NULL);
  1394. X    (void) notify_interpose_event_func(ignore_list_textsw,
  1395. X    fkey_interposer, NOTIFY_SAFE);
  1396. X
  1397. X    window_fit_height(ignore_frame);
  1398. X    update_list_textsw(&ignore_hdr);
  1399. X}
  1400. END_OF_FILE
  1401. if test 7659 -ne `wc -c <'mush/misc_frame.c'`; then
  1402.     echo shar: \"'mush/misc_frame.c'\" unpacked with wrong size!
  1403. fi
  1404. # end of 'mush/misc_frame.c'
  1405. fi
  1406. if test -f 'mush/strings.c' -a "${1}" != "-c" ; then 
  1407.   echo shar: Will not clobber existing file \"'mush/strings.c'\"
  1408. else
  1409. echo shar: Extracting \"'mush/strings.c'\" \(9988 characters\)
  1410. sed "s/^X//" >'mush/strings.c' <<'END_OF_FILE'
  1411. X/* strings.c Copyright(1988) Dan Heller */
  1412. X
  1413. X#include "mush.h"
  1414. X
  1415. X/*
  1416. X * reverse a string.  Useful for uucp-style address comparisons.
  1417. X */
  1418. Xchar *
  1419. Xreverse(s)
  1420. Xchar s[];
  1421. X{
  1422. X    int n = strlen(s), m;
  1423. X    char c;
  1424. X
  1425. X    if (n < 1)
  1426. X    return 0;
  1427. X    if (n & 1)
  1428. X    n = n/2 + 1, m = n - 2;
  1429. X    else
  1430. X    n /= 2, m = n - 1;
  1431. X    for ( ; m >= 0; m--, n++)
  1432. X    c = s[n], s[n] = s[m], s[m] = c;
  1433. X    return s;
  1434. X}
  1435. X
  1436. X/*
  1437. X * lose the newline character, trailing whitespace, and return the end of p
  1438. X * test for '\n' separately since some _ctype_[] arrays may not have the
  1439. X * _S bit set for the newline character.  see <ctype.h> for more info.
  1440. X */
  1441. Xchar *
  1442. Xno_newln(p)
  1443. Xregister char *p;
  1444. X{
  1445. X    register char *p2 = p + strlen(p);    /* point it to the null terminator */
  1446. X
  1447. X    while (p2 > p && *--p2 == '\n' || isspace(*p2))
  1448. X    *p2 = 0;  /* get rid of newline and trailing spaces */
  1449. X    return p2;
  1450. X}
  1451. X
  1452. X/* find any character in s1 that's in s2; return pointer to char in s1. */
  1453. Xchar *
  1454. Xany(s1, s2)
  1455. Xregister char *s1, *s2;
  1456. X{
  1457. X    register char *p;
  1458. X    if (!s1 || !*s1 || !s2 || !*s2)
  1459. X    return NULL;
  1460. X    for( ; *s1; s1++) {
  1461. X    for(p = s2; *p; p++)
  1462. X        if (*p == *s1)
  1463. X        return s1;
  1464. X    }
  1465. X    return NULL;
  1466. X}
  1467. X
  1468. X/* check two lists of strings each of which contain substrings.
  1469. X * Each substring is delimited by any char in "delimiters"
  1470. X * return true if any elements in list1 are on list2.
  1471. X * thus:
  1472. X * string1 = "foo, bar, baz"
  1473. X * string2 = "foobar, baz, etc"
  1474. X * delimiters = ", \t"
  1475. X * example returns 1 because "baz" exists in both lists
  1476. X * NOTE: case is ignored.
  1477. X */
  1478. Xchk_two_lists(list1, list2, delimiters)
  1479. Xregister char *list1, *list2, *delimiters;
  1480. X{
  1481. X    register char *p, c;
  1482. X    register int found = 0;
  1483. X
  1484. X    if (!list1 || !list2)
  1485. X    return 0;
  1486. X
  1487. X    if (p = any(list1, delimiters)) {
  1488. X    if (p > list1) {
  1489. X        c = *p; *p = 0;
  1490. X        /* Check list2 against the first word of list1.
  1491. X         * Swap places of list2 and list1 to step through list2.
  1492. X         */
  1493. X        found = chk_two_lists(list2, list1, delimiters);
  1494. X        *p = c;
  1495. X    }
  1496. X    if (found)
  1497. X        return 1;
  1498. X    for (p++; *p && index(delimiters, *p); p++)
  1499. X        ;
  1500. X    if (!*p)
  1501. X        return 0;
  1502. X    } else if (!any(list2, delimiters))
  1503. X    /* Do the trivial case of single words */
  1504. X    return !lcase_strncmp(list1, list2, -1);
  1505. X    else
  1506. X    p = list1;
  1507. X
  1508. X    /* Either only list2 has delims or the first word of list1
  1509. X     * did not match anything in list2.  Check list2 against the
  1510. X     * rest of list1.  This could be more efficient by using a
  1511. X     * different function to avoid repeating the any() calls.
  1512. X     */
  1513. X    return chk_two_lists(list2, p, delimiters);
  1514. X}
  1515. X
  1516. Xbzero(addr, size)
  1517. Xregister char *addr;
  1518. Xregister int size;
  1519. X{
  1520. X    while (size-- > 0)
  1521. X    addr[size] = 0;
  1522. X}
  1523. X
  1524. X/* do an atoi() on the string passed and return in "val" the decimal value.
  1525. X * the function returns a pointer to the location in the string that is not
  1526. X * a digit.
  1527. X */
  1528. Xchar *
  1529. Xmy_atoi(p, val)
  1530. Xregister char *p;
  1531. Xregister int *val;
  1532. X{
  1533. X    int positive = 1;
  1534. X
  1535. X    if (!p)
  1536. X    return NULL;
  1537. X    *val = 0;
  1538. X    if (*p == '-')
  1539. X    positive = -1, p++;
  1540. X    while (isdigit(*p))
  1541. X    *val = (*val) * 10 + *p++ - '0';
  1542. X    *val *= positive;
  1543. X    return p;
  1544. X}
  1545. X
  1546. X/* strcmp ignoring case */
  1547. Xlcase_strncmp(str1, str2, n)
  1548. Xregister char *str1, *str2;
  1549. X{
  1550. X    while (*str1 && *str2 && --n != 0)
  1551. X    if (lower(*str1) != lower(*str2))
  1552. X        break;
  1553. X    else
  1554. X        str1++, str2++;
  1555. X    return lower(*str1) - lower(*str2);
  1556. X}
  1557. X
  1558. X/* strcpy converting everything to lower case (arbitrary) to ignore cases */
  1559. Xchar *
  1560. Xlcase_strcpy(dst, src)
  1561. Xregister char *dst, *src;
  1562. X{
  1563. X    register char *s = dst;
  1564. X
  1565. X    /* "lower" is a macro, don't increment its argument! */
  1566. X    while (*dst++ = lower(*src))
  1567. X    src++;
  1568. X    return s;
  1569. X}
  1570. X
  1571. X/* this strcpy returns number of bytes copied */
  1572. XStrcpy(dst, src)
  1573. Xregister char *dst, *src;
  1574. X{
  1575. X    register int n = 0;
  1576. X    if (!dst || !src)
  1577. X    return 0;
  1578. X    while (*dst++ = *src++)
  1579. X    n++;
  1580. X    return n;
  1581. X}
  1582. X
  1583. Xchar *
  1584. Xsavestr(s)
  1585. Xregister char *s;
  1586. X{
  1587. X    register char *p;
  1588. X
  1589. X    if (!s)
  1590. X    s = "";
  1591. X    if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
  1592. X    error("out of memory saving %s", s);
  1593. X    return NULL;
  1594. X    }
  1595. X    return strcpy(p, s);
  1596. X}
  1597. X
  1598. X/* copy a vector of strings into one string -- return the end of the string */
  1599. Xchar *
  1600. Xargv_to_string(p, argv)
  1601. Xregister char *p, **argv;
  1602. X{
  1603. X    register int i;
  1604. X    register char *ptr = p;
  1605. X
  1606. X    *p = 0;
  1607. X    if (!argv[0])
  1608. X    return "";
  1609. X    for (i = 0; argv[i]; i++)
  1610. X    ptr += strlen(sprintf(ptr, "%s ", argv[i]));
  1611. X    *--ptr = 0;   /* get rid of the last space */
  1612. X    return ptr;
  1613. X}
  1614. X
  1615. Xchar *
  1616. Xitoa(n)
  1617. X{
  1618. X    static char buf[10];
  1619. X    return sprintf(buf, "%d", n);
  1620. X}
  1621. X
  1622. X/*
  1623. X * There are two different kinds of sprintf() --those that return char * and
  1624. X * those that return int.  System-V returns int (the length of the resulting
  1625. X * string).  BSD has historically returned a pointer to the resulting string
  1626. X * instead. Mush was originally written under BSD, so the usage has always
  1627. X * been to assume the char * method.  Because the system-v method is far more
  1628. X * useful, mush should some day change to use that method, but until then,
  1629. X * this routine was written to allow all the unix'es to appear the same to
  1630. X * the programmer regardless of which sprintf is actually used.  The "latest"
  1631. X * version of 4.3BSD (as of Fall 1988) has changed its format to go from the
  1632. X * historical BSD method to the sys-v method.  It is no longer possible to
  1633. X * simply #ifdef this routine for sys-v --it is now required to use this
  1634. X * routine regardless of which sprintf is notice to your machine.  However,
  1635. X * if you know your system's sprintf returns a char *, you can remove the
  1636. X * define in strings.h
  1637. X */
  1638. X#include <varargs.h>
  1639. X/*VARARGS*/
  1640. X/*ARGSUSED*/
  1641. Xchar *
  1642. XSprintf(va_alist)
  1643. Xva_dcl
  1644. X{
  1645. X    char *buf, *fmt;
  1646. X    va_list ap;
  1647. X
  1648. X    va_start(ap);
  1649. X    buf = va_arg(ap, char *);
  1650. X    fmt = va_arg(ap, char *);
  1651. X#ifdef VPRINTF
  1652. X    (void) vsprintf(buf, fmt, ap);
  1653. X#else
  1654. X    {
  1655. X    FILE foo;
  1656. X    foo._cnt = BUFSIZ;
  1657. X    foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
  1658. X    foo._flag = _IOWRT+_IOSTRG;
  1659. X    (void) _doprnt(fmt, ap, &foo);
  1660. X    *foo._ptr = '\0'; /* plant terminating null character */
  1661. X    }
  1662. X#endif /* VPRINTF */
  1663. X    va_end(ap);
  1664. X    return buf;
  1665. X}
  1666. X
  1667. Xvoid
  1668. Xprint_argv(argv)
  1669. Xchar **argv;
  1670. X{
  1671. X    while (*argv)
  1672. X    if (debug)
  1673. X        wprint("(%s) ", *argv++);
  1674. X    else
  1675. X        wprint("%s ", *argv++);
  1676. X    wprint("\n");
  1677. X}
  1678. X
  1679. X/*
  1680. X * putstring -- put a string into a file.  Expand \t's into tabs and \n's
  1681. X * into newlines.  Append a \n and fflush(fp);
  1682. X */
  1683. Xvoid
  1684. Xputstring(p, fp)
  1685. Xregister char *p;
  1686. Xregister FILE *fp;
  1687. X{
  1688. X    for ( ; *p; ++p)
  1689. X    if (*p != '\\')
  1690. X        (void) fputc(*p, fp);
  1691. X    else
  1692. X        switch(*++p) {
  1693. X        case 'n': (void) fputc('\n', fp);
  1694. X        when 't': (void) fputc('\t', fp);
  1695. X        otherwise: (void) fputc(*p, fp);
  1696. X        }
  1697. X    (void) fputc('\n', fp);
  1698. X    (void) fflush(fp);
  1699. X}
  1700. X
  1701. X#define chtoi(c)    ((int)(c) - (int)'0')
  1702. X
  1703. X/* m_xlate(str) converts strings of chars which contain ascii representations
  1704. X *  of control characters appearing in str into the literal characters they
  1705. X *  represent.  The usual curses-mode character expansions (\Cx -> control-x)
  1706. X *  are honored, as are most C escapes.  Unrecognized portions are unchanged.
  1707. X */
  1708. Xchar *
  1709. Xm_xlate (str)
  1710. Xregister char *str;
  1711. X{
  1712. X    register char *r, *s, *t;
  1713. X    int dv, nd;
  1714. X
  1715. X    /*
  1716. X     * r will receive the new string, s will track the old one,
  1717. X     *  and t will step through escape sequences
  1718. X     * This allows the translation to be done in place
  1719. X     */
  1720. X    r = s = str;
  1721. X    while (s && *s) {
  1722. X    if (*s == '\\') {
  1723. X        t = s + 1;
  1724. X        /*
  1725. X         * After each case below, t should point to the character
  1726. X         *  following the escape sequence
  1727. X         */
  1728. X        switch(*t) {
  1729. X        case '\0' :
  1730. X            /*
  1731. X             * Hmmm ... a backslash followed by the string
  1732. X             *  terminator.  Copy the backslash ONLY.
  1733. X             */
  1734. X            *r++ = *s++;
  1735. X            break;
  1736. X        case '0' :
  1737. X        case '1' :
  1738. X        case '2' :
  1739. X        case '3' :
  1740. X        case '4' :
  1741. X        case '5' :
  1742. X        case '6' :
  1743. X        case '7' :
  1744. X            /*
  1745. X             * Convert up to 3 octal digits to their ascii value
  1746. X             */
  1747. X            dv = chtoi(*t++);
  1748. X            for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
  1749. X            if (chtoi(*t) < 8)
  1750. X                dv = (8 * dv) + chtoi(*t++);
  1751. X            else
  1752. X                break;
  1753. X            if (dv < 256 && dv > 0)
  1754. X            /* Valid octal number escaped */
  1755. X            *r++ = (char)dv;
  1756. X            else
  1757. X            /* Invalid octal number, so copy unchanged */
  1758. X            while (s < t)
  1759. X                *r++ = *s++;
  1760. X            break;
  1761. X        case 'b' :
  1762. X            *r++ = '\b';
  1763. X            t++;
  1764. X            break;
  1765. X        case 'C' :
  1766. X            t++;
  1767. X            if (*t == '?')
  1768. X            *r++ = '\177';
  1769. X            else if (*t == '~')
  1770. X            *r++ = '\036';
  1771. X            else if (*t == '/')
  1772. X            *r++ = '\037';
  1773. X            else if (isalpha(*t) || *t > '\132' && *t < '\140')
  1774. X            *r++ = *t & 037;
  1775. X            else
  1776. X            while (s <= t) *r++ = *s++;
  1777. X            t++;
  1778. X            break;
  1779. X        case 'E' :
  1780. X            *r++ = '\033';
  1781. X            t++;
  1782. X            break;
  1783. X        case 'f' :
  1784. X            *r++ = '\f';
  1785. X            t++;
  1786. X            break;
  1787. X        case 'n' :
  1788. X            *r++ = '\n';
  1789. X            t++;
  1790. X            break;
  1791. X        case 'r' :
  1792. X            *r++ = '\r';
  1793. X            t++;
  1794. X            break;
  1795. X        case 't' :
  1796. X            *r++ = '\t';
  1797. X            t++;
  1798. X            break;
  1799. X        case '\\' :
  1800. X            *r++ = *t++;
  1801. X            break;
  1802. X        default :
  1803. X            /*
  1804. X             * Not recognized, so copy both characters
  1805. X             */
  1806. X            *r++ = *s++;
  1807. X            *r++ = *s++;
  1808. X            break;
  1809. X        }
  1810. X        /*
  1811. X         * Now make sure s also points to the character after the
  1812. X         *  escape sequence, by comparing to t
  1813. X         */
  1814. X        if (t > s)
  1815. X        s = t;
  1816. X    } else
  1817. X        *r++ = *s++;
  1818. X    }
  1819. X    *r = '\0';
  1820. X    return str;
  1821. X}
  1822. X
  1823. X/*
  1824. X * Convert control characters to ascii format (reverse effect of m_xlate()).
  1825. X */
  1826. Xchar *
  1827. Xctrl_strcpy(s_out, s_in, bind_format)
  1828. Xregister char *s_out, *s_in;
  1829. X{
  1830. X#if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
  1831. X    extern char *_unctrl[];
  1832. X#endif /* !M_XENIX || M_XENIX && !CURSES */
  1833. X    char *start = s_out;
  1834. X
  1835. X    for (; *s_in; s_in++)
  1836. X    if (*s_in == '\n')
  1837. X        *s_out++ = '\\', *s_out++ = 'n';
  1838. X    else if (*s_in == '\r')
  1839. X        *s_out++ = '\\', *s_out++ = 'r';
  1840. X    else if (*s_in == '\t')
  1841. X        *s_out++ = '\\', *s_out++ = 't';
  1842. X    else if (*s_in == ESC)
  1843. X        *s_out++ = '\\', *s_out++ = 'E';
  1844. X    else if (iscntrl(*s_in)) {
  1845. X        if (bind_format)
  1846. X        *s_out++ = '\\', *s_out++ = 'C';
  1847. X        else
  1848. X        *s_out++ = '^';
  1849. X        *s_out++ = _unctrl[*s_in][1];
  1850. X    } else
  1851. X        *s_out++ = *s_in;
  1852. X    *s_out = 0;
  1853. X    return start;
  1854. X}
  1855. END_OF_FILE
  1856. if test 9988 -ne `wc -c <'mush/strings.c'`; then
  1857.     echo shar: \"'mush/strings.c'\" unpacked with wrong size!
  1858. fi
  1859. # end of 'mush/strings.c'
  1860. fi
  1861. echo shar: End of archive 17 \(of 19\).
  1862. cp /dev/null ark17isdone
  1863. MISSING=""
  1864. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1865.     if test ! -f ark${I}isdone ; then
  1866.     MISSING="${MISSING} ${I}"
  1867.     fi
  1868. done
  1869. if test "${MISSING}" = "" ; then
  1870.     echo You have unpacked all 19 archives.
  1871.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1872. else
  1873.     echo You still need to unpack the following archives:
  1874.     echo "        " ${MISSING}
  1875. fi
  1876. ##  End of shell archive.
  1877. exit 0
  1878.  
  1879.